from operator import is_
import gym
import numpy as np
from gym import spaces
from gym.utils import seeding


class flappybird(gym.Env):
    def __init__(self, touch_ground_reward=-1, touch_top_reward=-1, touch_pipe_reward=-1, pass_pipe_reward=1, normal_reward=0, near_pipe_reward=1.0):
        self.action_space = spaces.Discrete(2)
        self.observation_space = spaces.Box(
            low=0, high=100, shape=(4,), dtype=np.float32
        )  # 4维状态空间
        self.state = np.zeros(4)
        self.flap_acc = -9
        self.max_vel_y = 10
        self.min_vel_y = -8
        self.min_y = 0
        self.max_y = 400
        self.acc_y = 1
        self.touch_ground_reward = touch_ground_reward
        self.touch_top_reward = touch_top_reward
        self.touch_pipe_reward = touch_pipe_reward
        self.pass_pipe_reward = pass_pipe_reward
        self.normal_reward = normal_reward
        self.near_pipe_reward = near_pipe_reward

        self.seed()
        self.reset()

    def seed(self, seed=None):
        self.np_random, seed = seeding.np_random(seed)
        return [seed]

    def clamp(self, x, min, max):
        if x < min:
            return min
        if x > max:
            return max
        return x

    def step(self, action):
        assert self.action_space.contains(action)
        if action == 1:
            self.state[0] = self.flap_acc
        elif self.state[0] < self.max_vel_y:
            self.state[0] += self.acc_y
        self.state[1] = self.clamp(
            self.state[1] + self.state[0], self.min_y, self.max_y
        )
        self.state[2] -= 5
        if self.state[2] <= -26:
            self.state[2] = 200
            self.state[3] = self.np_random.random_integers(100, 300)

        reward = self.normal_reward
        done = False
        if abs(self.state[3] - self.state[1]) < 60:
            reward = self.near_pipe_reward
        if self.state[2] < 0:
            if abs(self.state[3] - self.state[1]) > 60:
                reward = self.touch_pipe_reward
                done = True
            else:
                reward = self.pass_pipe_reward

        if self.state[1] < 1.0:
            reward = self.touch_top_reward
        if self.state[1] > 390:
            reward = self.touch_ground_reward
            done = True

        return self.state, reward, done, {}

    def reset(self):
        self.state[0] = 0
        self.state[1] = self.np_random.random_integers(100, 300)
        self.state[2] = 200
        self.state[3] = self.np_random.random_integers(150, 250)
        return self.state

    def render(self, mode="human"):
        pass

    def close(self):
        pass
